﻿namespace HiMap.MapControls
{
    using HiMap.Carto;
    using HiMap.Geometry;
    using HiMap.MapControls.Tools;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    public class MapControl : UserControl
    {
        private Bitmap _bmpFlash;
        private int _countFlash;
        private ITool _CurTool;
        private EditEnvironmentClass _editEnvironment;
        private Image _imgFlash;
        private int _indexFlash;
        private bool _IsMapRefresh;
        private HiMap.Carto.Map _Map;
        private IFeature _SelectedFeature;
        private IContainer components;
        protected internal Graphics g;
        internal int GoToIndex;
        protected internal IntPtr HDC = IntPtr.Zero;
        internal List<IEnvelope> lsitEnvelope;
        private DrawWork m_drawwork;
        protected internal PictureBox picMap;
        private Point StaPt;
        private Timer timerFlash;

        public event AfterMapRefreshEvent AfterMapRefresh;

        public event BeforeMapRefreshEvent BeforeMapRefresh;

        public event EventHandler MapChanged;

        public event EventHandler ToolUpdated;

        public MapControl()
        {
            this.InitializeComponent();
            this.m_drawwork = new DrawWork();
            this._Map = null;
            this._CurTool = null;
            this.lsitEnvelope = new List<IEnvelope>();
            this.GoToIndex = 0;
            this.StaPt = new Point();
            this._IsMapRefresh = false;
            this.MapChanged = (EventHandler) Delegate.Combine(this.MapChanged, new EventHandler(this.OnMapChanged));
            this.BeforeMapRefresh = (BeforeMapRefreshEvent) Delegate.Combine(this.BeforeMapRefresh, new BeforeMapRefreshEvent(this.OnBeforeMapRefresh));
            this.AfterMapRefresh = (AfterMapRefreshEvent) Delegate.Combine(this.AfterMapRefresh, new AfterMapRefreshEvent(this.OnAfterMapRefresh));
        }

        internal void AfterView()
        {
            if ((this.GoToIndex + 1) <= (this.lsitEnvelope.Count - 1))
            {
                this.GoToIndex++;
                this.Map.Envelope = this.lsitEnvelope[this.GoToIndex];
                if (KWG_DRAWWORK_DRAWMAP(this.m_drawwork.DrawInptr, this.Map.InPtr) && KWG_DRAWWORK_PAINT(this.m_drawwork.DrawInptr, this.HDC, 0, 0))
                {
                    this.picMap.Refresh();
                }
            }
        }

        internal void BeforeView()
        {
            if (this.GoToIndex > 0)
            {
                this.GoToIndex--;
            }
            this.Map.Envelope = this.lsitEnvelope[this.GoToIndex];
            if (KWG_DRAWWORK_DRAWMAP(this.m_drawwork.DrawInptr, this.Map.InPtr) && KWG_DRAWWORK_PAINT(this.m_drawwork.DrawInptr, this.HDC, 0, 0))
            {
                this.picMap.Refresh();
            }
        }

        private void ClearToolEvent(ITool obj)
        {
            base.DoubleClick -= new EventHandler(obj.OnDoubleClick);
            base.MouseDown -= new MouseEventHandler(obj.OnMouseDown);
            base.MouseMove -= new MouseEventHandler(obj.OnMouseMove);
            base.MouseUp -= new MouseEventHandler(obj.OnMouseUp);
            this.ToolUpdated = (EventHandler) Delegate.Remove(this.ToolUpdated, new EventHandler(obj.OnToolUpdated));
        }

        private void CreateToolEvent(ITool obj)
        {
            base.DoubleClick += new EventHandler(obj.OnDoubleClick);
            base.MouseDown += new MouseEventHandler(obj.OnMouseDown);
            base.MouseMove += new MouseEventHandler(obj.OnMouseMove);
            base.MouseUp += new MouseEventHandler(obj.OnMouseUp);
            this.ToolUpdated = (EventHandler) Delegate.Combine(this.ToolUpdated, new EventHandler(obj.OnToolUpdated));
        }

        public void Destory()
        {
            if (this.Map != null)
            {
                this.Map.Destory();
                this.Map = null;
            }
            if (this.HDC != IntPtr.Zero)
            {
                this.g.ReleaseHdc(this.HDC);
            }
            this.m_drawwork.Destory();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (this.components != null))
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }

        public void DrawEllipse(Pen pen, Rectangle rect)
        {
            this.g.DrawEllipse(pen, rect);
            this.picMap.Refresh();
        }

        public void DrawEllipse(Pen pen, int x, int y, int width, int height)
        {
            this.g.DrawEllipse(pen, x, y, width, height);
            this.picMap.Refresh();
        }

        public void DrawImage(Image img, int x, int y, int width, int height, Color transcolor)
        {
            Graphics graphics = Graphics.FromImage(img);
            IntPtr hdc = graphics.GetHdc();
            int crTransparent = (transcolor.R + (transcolor.G * 0x100)) + ((transcolor.B * 0x100) * 0x100);
            HiMap.MapControls.VC.KWGTransparentBlt2(this.HDC.ToInt32(), x, y, width, height, hdc.ToInt32(), 0, 0, img.Width, img.Height, crTransparent);
            graphics.ReleaseHdc(hdc);
            this.picMap.Refresh();
        }

        public void DrawLine(Pen pen, IPoint[] pts)
        {
            Point[] pointArray = new Point[pts.Length];
            pointArray = this.MapToScreen(pts);
            this.DrawLine(pen, pointArray);
        }

        public void DrawLine(Pen pen, Point[] pts)
        {
            this.g.DrawLines(pen, pts);
            this.picMap.Refresh();
        }

        public void DrawLine(Pen pen, Point pt1, Point pt2)
        {
            this.g.DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y);
            this.picMap.Refresh();
        }

        public void DrawPoint(Pen pen, Brush brush, Rectangle rect)
        {
            this.g.FillEllipse(brush, rect);
            this.g.DrawEllipse(pen, rect);
            this.picMap.Refresh();
        }

        public void DrawPoint(Pen pen, Brush brush, double x, double y, int size)
        {
            Point point = this.MapToScreen(x, y);
            this.DrawPoint(pen, brush, new Rectangle(point.X - (size / 2), point.Y - (size / 2), size, size));
        }

        public void DrawPolygon(Pen pen, Brush brush, IPoint[] pts)
        {
            this.DrawPolygon(pen, brush, this.MapToScreen(pts));
        }

        public void DrawPolygon(Pen pen, Brush brush, Point[] pts)
        {
            this.g.FillPolygon(brush, pts);
            this.g.DrawPolygon(pen, pts);
            this.picMap.Refresh();
        }

        public void DrawRectangle(Pen pen, Rectangle rect)
        {
            this.g.DrawRectangle(pen, rect);
            this.picMap.Refresh();
        }

        public void DrawString(string s, Font font, Brush brush, float x, float y)
        {
            this.g.DrawString(s, font, brush, x, y);
            this.picMap.Refresh();
        }

        ~MapControl()
        {
        }

        private void Flash(Bitmap bmp, int count, int val)
        {
            this._imgFlash = bmp;
            this._countFlash = count;
            this._indexFlash = 0;
            this.timerFlash.Interval = val / 2;
            this.timerFlash.Enabled = true;
        }

        public void Flash(IGeometry geo, Color color, int count, int val)
        {
            this.Flash(null, count, val);
            this._bmpFlash = new Bitmap(this.picMap.Image);
            Graphics gg = Graphics.FromImage(this._bmpFlash);
            this.InFlashBmp(gg, color, geo);
            this.Flash(this._bmpFlash, count, val);
            gg.Dispose();
        }

        public void Flash(List<IFeature> cur, Color color, int count, int val)
        {
            this._bmpFlash = new Bitmap(this.picMap.Image);
            Graphics gg = Graphics.FromImage(this._bmpFlash);
            for (int i = 0; i < cur.Count; i++)
            {
                IGeometry geo = cur[i].Shape;
                if (geo != null)
                {
                    this.InFlashBmp(gg, color, geo);
                }
            }
            this.Flash(this._bmpFlash, count, val);
            gg.Dispose();
        }

        public void Flash(IFeatureCursor cur, Color color, int count, int val)
        {
            this._bmpFlash = new Bitmap(this.picMap.Image);
            Graphics gg = Graphics.FromImage(this._bmpFlash);
            cur.Flush();
            for (IFeature feature = cur.Next(); feature != null; feature = cur.Next())
            {
                IGeometry geo = feature.Shape;
                if (geo != null)
                {
                    this.InFlashBmp(gg, color, geo);
                }
            }
            this.Flash(this._bmpFlash, count, val);
            gg.Dispose();
        }

        public void Flash(List<IFeatureCursor> list, Color color, int count, int val)
        {
            this._bmpFlash = new Bitmap(this.picMap.Image);
            Graphics gg = Graphics.FromImage(this._bmpFlash);
            for (int i = 0; i < list.Count; i++)
            {
                IFeatureCursor cursor = list[i];
                cursor.Flush();
                for (IFeature feature = cursor.Next(); feature != null; feature = cursor.Next())
                {
                    IGeometry geo = feature.Shape;
                    if (geo != null)
                    {
                        this.InFlashBmp(gg, color, geo);
                    }
                }
            }
            this.Flash(this._bmpFlash, count, val);
            gg.Dispose();
        }

        private void FlashBmp(Graphics gg, Color color, IGeometry geo)
        {
            Point[] points = this.GetFlashPoint(geo);
            switch (geo.Type)
            {
                case GeometryType.Point:
                    gg.FillRectangle(new SolidBrush(color), points[0].X - 4, points[0].Y - 4, 9, 9);
                    return;

                case GeometryType.MultiPoint:
                    break;

                case GeometryType.Polyline:
                    gg.DrawLines(new Pen(color, 2f), points);
                    break;

                case GeometryType.Polygon:
                    gg.FillPolygon(new SolidBrush(color), points);
                    return;

                case GeometryType.Envelope:
                    gg.FillRectangle(new SolidBrush(color), points[0].X, points[0].Y, points[1].X - points[0].X, points[1].Y - points[0].Y);
                    return;

                default:
                    return;
            }
        }

        private Point[] GetFlashPoint(IGeometry geo)
        {
            Point[] pointArray;
            IPointCollection points = null;
            if (geo.Type == GeometryType.Point)
            {
                pointArray = new Point[1];
                IPoint point = (IPoint) geo;
                pointArray[0] = this.MapToScreen(point.X, point.Y);
                return pointArray;
            }
            if (geo.Type == GeometryType.Envelope)
            {
                pointArray = new Point[2];
                IEnvelope envelope = (IEnvelope) geo;
                pointArray[0] = this.MapToScreen(envelope.MinX, envelope.MinY);
                pointArray[1] = this.MapToScreen(envelope.MaxX, envelope.MaxY);
                return pointArray;
            }
            if (geo.Type == GeometryType.MultiPoint)
            {
                pointArray = new Point[1];
                IMultiPoint point2 = (IMultiPoint) geo;
                pointArray[0] = this.MapToScreen(point2.X, point2.Y);
                return pointArray;
            }
            points = (IPointCollection) geo;
            pointArray = new Point[points.PointCount];
            IPoint point3 = null;
            for (int i = 0; i < points.PointCount; i++)
            {
                point3 = points.GetPoint(i);
                pointArray[i] = this.MapToScreen(point3.X, point3.Y);
            }
            return pointArray;
        }

        private void InFlashBmp(Graphics gg, Color color, IGeometry geo)
        {
            if (((geo.Type == GeometryType.MultiPoint) || (geo.Type == GeometryType.Polygon)) || (geo.Type == GeometryType.Polyline))
            {
                IGeometryCollection geometrys = (IGeometryCollection) geo;
                for (int i = 0; i < geometrys.GeometryCount; i++)
                {
                    this.FlashBmp(gg, color, geometrys.GetGeometry(i));
                }
            }
            else
            {
                this.FlashBmp(gg, color, geo);
            }
        }

        private void InitializeComponent()
        {
            this.picMap = new PictureBox();
            this.timerFlash = new Timer();
            base.SuspendLayout();
            this.picMap.BackColor = Color.Gainsboro;
            this.picMap.Dock = DockStyle.Fill;
            this.picMap.Location = new Point(0, 0);
            this.picMap.Name = "picMap";
            this.picMap.Size = new Size(150, 150);
            this.picMap.DoubleClick += new EventHandler(this.picMap_DoubleClick);
            this.picMap.LostFocus += new EventHandler(this.picMap_LostFocus);
            this.picMap.Click += new EventHandler(this.picMap_Click);
            this.picMap.MouseDown += new MouseEventHandler(this.picMap_MouseDown);
            this.picMap.MouseMove += new MouseEventHandler(this.picMap_MouseMove);
            this.picMap.GotFocus += new EventHandler(this.picMap_GotFocus);
            this.picMap.Resize += new EventHandler(this.picMap_Resize);
            this.picMap.ParentChanged += new EventHandler(this.picMap_ParentChanged);
            this.picMap.MouseUp += new MouseEventHandler(this.picMap_MouseUp);
            this.picMap.EnabledChanged += new EventHandler(this.picMap_EnabledChanged);
            this.timerFlash.Tick += new EventHandler(this.timerFlash_Tick);
            base.AutoScaleDimensions = new SizeF(96f, 96f);
            base.AutoScaleMode = AutoScaleMode.Dpi;
            this.BackColor = Color.White;
            base.Controls.Add(this.picMap);
            base.Name = "MapControl";
            base.ResumeLayout(false);
        }

        public bool IsMapPointInEnvelope(double x, double y)
        {
            return (((x > this.Map.Envelope.MinX) && (x < this.Map.Envelope.MaxX)) && ((y > this.Map.Envelope.MinY) && (y < this.Map.Envelope.MaxY)));
        }

        [DllImport("KMGisLib")]
        public static extern void KWG_DRAWWORK_DELETE(int drawwork_ptr);
        [DllImport("KMGisLib")]
        public static extern bool KWG_DRAWWORK_DRAWMAP(int drawwork_ptr, int map_ptr);
        [DllImport("KMGisLib")]
        public static extern bool KWG_DRAWWORK_PAINT(int drawwork_ptr, IntPtr hdc, int offx, int offy);
        public void MapRefresh()
        {
            MapEventArgs e = new MapEventArgs();
            try
            {
                if (this.Map != null)
                {
                    this._IsMapRefresh = true;
                    this._Map.SetFrameBound(base.Width, base.Height);
                    e.m_hdc = this.HDC;
                    e.m_envlope = this.Map.Envelope;
                    e.m_width = base.Width;
                    e.m_height = base.Height;
                    this.BeforeMapRefresh(e);
                    Cursor.Current = Cursors.WaitCursor;
                    if (this.lsitEnvelope.Count == 0)
                    {
                        this.lsitEnvelope.Add(this.Map.Envelope);
                    }
                    if (this.Map.EnvelopeUpdate)
                    {
                        if (this.GoToIndex != (this.lsitEnvelope.Count - 1))
                        {
                            this.lsitEnvelope = new List<IEnvelope>();
                            this.lsitEnvelope.Add(this.Map.Envelope);
                        }
                        this.lsitEnvelope.Add(this.Map.Envelope);
                        this.GoToIndex = this.lsitEnvelope.Count - 1;
                        this.Map.EnvelopeUpdate = false;
                    }
                    if (KWG_DRAWWORK_DRAWMAP(this.m_drawwork.DrawInptr, this.Map.InPtr) && KWG_DRAWWORK_PAINT(this.m_drawwork.DrawInptr, this.HDC, 0, 0))
                    {
                        this.picMap.Refresh();
                        Cursor.Current = Cursors.Default;
                        this._IsMapRefresh = false;
                    }
                    this._editEnvironment.EnvironmentUpdate();
                }
            }
            catch
            {
            }
            this.AfterMapRefresh(e);
            this.picMap.Refresh();
        }

        internal void MapRefresh(int offX, int offY)
        {
            try
            {
                KWG_DRAWWORK_PAINT(this.m_drawwork.DrawInptr, this.HDC, offX, offY);
                this.picMap.Refresh();
            }
            catch
            {
            }
        }

        public void MapRefreshNoRePaint()
        {
            MapEventArgs e = new MapEventArgs();
            try
            {
                if ((this.Map != null) && (0 < this.Map.LayerCount))
                {
                    this._IsMapRefresh = true;
                    e.m_hdc = this.HDC;
                    e.m_envlope = this.Map.Envelope;
                    e.m_width = base.Width;
                    e.m_height = base.Height;
                    this.BeforeMapRefresh(e);
                    KWG_DRAWWORK_PAINT(this.m_drawwork.DrawInptr, this.HDC, 0, 0);
                    this._IsMapRefresh = false;
                }
            }
            catch
            {
            }
            this.AfterMapRefresh(e);
            this.picMap.Refresh();
        }

        public Point[] MapToScreen(IPoint[] pts)
        {
            return this._Map.MapToScreen(pts);
        }

        public Point MapToScreen(double x, double y)
        {
            return this._Map.MapToScreen(x, y);
        }

        public void MoveToMapPoint(double x, double y)
        {
            if ((x != 0) || (y != 0))
            {
                double num = this._Map.Envelope.MaxX - this._Map.Envelope.MinX;
                double num2 = this._Map.Envelope.MaxY - this._Map.Envelope.MinY;
                IEnvelope envelope = new EnvelopeClass();
                envelope.MinX = x - ((num / ((double) base.Size.Width)) * (base.Size.Width / 2));
                envelope.MaxX = x + ((num / ((double) base.Size.Width)) * (base.Size.Width / 2));
                envelope.MinY = y + ((num2 / ((double) base.Size.Height)) * (base.Size.Height / 2));
                envelope.MaxY = y - ((num2 / ((double) base.Size.Height)) * (base.Size.Height / 2));
                this._Map.Envelope = envelope;
                this.MapRefresh();
            }
        }

        private void OnAfterMapRefresh(MapEventArgs e)
        {
        }

        private void OnBeforeMapRefresh(MapEventArgs e)
        {
        }

        private void OnMapChanged(object sender, EventArgs e)
        {
        }

        private void picMap_Click(object sender, EventArgs e)
        {
            this.OnClick(e);
        }

        private void picMap_DoubleClick(object sender, EventArgs e)
        {
            this.OnDoubleClick(e);
        }

        private void picMap_EnabledChanged(object sender, EventArgs e)
        {
            this.OnEnabledChanged(e);
        }

        private void picMap_GotFocus(object sender, EventArgs e)
        {
            this.OnGotFocus(e);
        }

        private void picMap_LostFocus(object sender, EventArgs e)
        {
            this.OnLostFocus(e);
        }

        private void picMap_MouseDown(object sender, MouseEventArgs e)
        {
            this.OnMouseDown(e);
            this.StaPt.X = e.X;
            this.StaPt.Y = e.Y;
        }

        private void picMap_MouseMove(object sender, MouseEventArgs e)
        {
            this.OnMouseMove(e);
        }

        private void picMap_MouseUp(object sender, MouseEventArgs e)
        {
            this.OnMouseUp(e);
        }

        private void picMap_ParentChanged(object sender, EventArgs e)
        {
            this.OnParentChanged(e);
        }

        private void picMap_Resize(object sender, EventArgs e)
        {
            if ((this.picMap.Image != null) && ((this.picMap.Image.Width != this.picMap.Width) || (this.picMap.Image.Height != this.picMap.Height)))
            {
                this.picMap.Image = null;
                if (this.HDC != IntPtr.Zero)
                {
                    this.g.ReleaseHdc(this.HDC);
                    this.g.Dispose();
                    this.HDC = IntPtr.Zero;
                }
            }
            if (this.picMap.Image == null)
            {
                this.picMap.Image = Image.FromHbitmap(new Bitmap(base.Width, base.Height).GetHbitmap());
                this.g = Graphics.FromImage(this.picMap.Image);
                this.g.Clear(Color.White);
                this.HDC = this.g.GetHdc();
            }
            this.OnResize(e);
        }

        public IPoint PointToMapPoint(int x, int y)
        {
            return this._Map.PointToMapPoint(x, y);
        }

        private void timerFlash_Tick(object sender, EventArgs e)
        {
            if (this._indexFlash < (this._countFlash * 2))
            {
                if ((this._indexFlash % 2) == 0)
                {
                    this.g.DrawImage(this._imgFlash, 0, 0);
                }
                else
                {
                    this.MapRefresh(0, 0);
                }
                this.picMap.Refresh();
            }
            else
            {
                this.picMap.Refresh();
                this._bmpFlash.Dispose();
                this._imgFlash.Dispose();
                this.timerFlash.Enabled = false;
            }
            this._indexFlash++;
        }

        public System.Windows.Forms.ContextMenu ContextMenu
        {
            get
            {
                return this.picMap.ContextMenu;
            }
            set
            {
                this.picMap.ContextMenu = value;
            }
        }

        public ITool CurTool
        {
            get
            {
                return this._CurTool;
            }
            set
            {
                if (this._CurTool != null)
                {
                    this._CurTool.OnToolUpdated(this._CurTool, null);
                    this.ClearToolEvent(this._CurTool);
                }
                this._CurTool = value;
                this.CreateToolEvent(this._CurTool);
            }
        }

        public IEditEnvironment editEnvironment
        {
            get
            {
                if (this._editEnvironment == null)
                {
                    Form frm = null;
                    for (Control parent = base.Parent; parent != null; parent = parent.Parent)
                    {
                        if (parent.GetType().BaseType.Name.ToUpper() == "FORM")
                        {
                            frm = (Form) parent;
                            break;
                        }
                    }
                    this._editEnvironment = new EditEnvironmentClass(frm, this);
                }
                return this._editEnvironment;
            }
        }

        public bool IsMapRefresh
        {
            get
            {
                return this._IsMapRefresh;
            }
        }

        public HiMap.Carto.Map Map
        {
            get
            {
                return this._Map;
            }
            set
            {
                this._Map = value;
                if (this._Map != null)
                {
                    this._Map.SetFrameBound(base.Width, base.Height);
                    this.MapChanged(value, null);
                }
            }
        }

        protected internal Image MapImage
        {
            get
            {
                return this.picMap.Image;
            }
            set
            {
                this.picMap.Image = value;
            }
        }

        public double MapScale
        {
            get
            {
                return this.Map.MapScale;
            }
        }

        public IFeature SelectedFeature
        {
            get
            {
                return this._SelectedFeature;
            }
            set
            {
                this._SelectedFeature = value;
            }
        }

        public delegate void AfterMapRefreshEvent(MapEventArgs e);

        public delegate void BeforeMapRefreshEvent(MapEventArgs e);
    }
}

